import { JwtPayload, JwtPayloadDto } from '@boticord/auth'
import { ChatMessageAuthor, ErrorCodes } from '@boticord/consts'
import { ChatMessage, PendingBot } from '@boticord/resources-client'
import { PostChatMessageDto } from '@boticord/resources-client/dto/post-chat-message.dto'
import { Body, Controller, ForbiddenException, Get, NotFoundException, Param, Post } from '@nestjs/common'
import { InjectRepository } from '@nestjs/typeorm'
import { Repository } from 'typeorm'
import { User } from '@boticord/users-client'

@Controller('bots/:id/chat')
export class ChatController {
  constructor(
    @InjectRepository(ChatMessage) private readonly messages: Repository<ChatMessage>,
    @InjectRepository(PendingBot) private readonly pendingBots: Repository<PendingBot>,
    @InjectRepository(User) private readonly users: Repository<User>,
  ) {}

  @Get()
  async getChatMessages(@Param('id') id: string) {
    return await this.messages.find({ where: { bot: id }, relations: { author: true }, order: { at: 'DESC' } })
  }

  @Post()
  async postChatMessage(
    @Param('id') id: string, 
    @JwtPayload() payload: JwtPayloadDto, 
    @Body() message: PostChatMessageDto,
  ) {
    const bot = await this.pendingBots.findOne({ where: { id }, relations: { developers: true } })

    if (bot === null) {
      throw new NotFoundException({ code: ErrorCodes.UnknownBot })
    }

    const user = await this.users.findOne({
      where: { id: payload.id }, select: [ 'id', 'username', 'avatar', 'discriminator' ],
    })

    if (user === null) {
      throw new NotFoundException({ code: ErrorCodes.UnknownUser })
    }
    
    let role: ChatMessageAuthor

    if (bot.developers.map(x => x.id).includes(payload.id) || bot.owner === payload.id) {
      role = ChatMessageAuthor.Developer
    } else {
      role = ChatMessageAuthor.Support
    }

    // fetch messages using typeorm sort by date and limit to 5
    const messages = await this.messages.find({
      where: { bot: id }, relations: { author: true }, order: { at: 'DESC' }, take: 2,
    })

    if (!this.canSendAs(payload.id, messages)) {
      throw new ForbiddenException({ code: ErrorCodes.TooManyConsecutiveMessages })
    }

    const msg = new ChatMessage()
    msg.at = new Date()
    msg.bot = bot.id
    msg.content = message.content
    msg.from = role
    msg.author = user

    return this.messages.save(msg)
  }

  // pass only two last messages
  private canSendAs(id: string, messages: ChatMessage[]) {
    if (messages.length < 2) {
      return true
    }

    return !messages.every(msg => msg.author.id === id)
  }
}
